package net.woggle.shackbrowse;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.woggle.shackbrowse.donate.IabHelper;
import net.woggle.shackbrowse.donate.IabResult;
import net.woggle.shackbrowse.donate.Inventory;
import net.woggle.shackbrowse.donate.Purchase;
import net.woggle.shackbrowse.legacy.LegacyFactory;

import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.MenuItem;
import com.google.android.gms.gcm.GoogleCloudMessaging;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Bitmap.CompressFormat;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.support.v4.app.TaskStackBuilder;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;


/**
 */
public class DonateActivity extends SherlockActivity {
    // Debug tag, for logging
    static final String TAG = "ShackBrowseDonate";

    // Does the user have the premium upgrade?
    boolean mIsUnlocked = false;
    boolean mHasChecked = false;
   
    // SKUs for our products: the premium upgrade (non-consumable) and gas (consumable)
    static final String SKU_DONATE_UNLOCK = "donate_unlock";
    static final String SKU_DONATE_EXTRA = "donate_extra";

    // (arbitrary) request code for the purchase flow
    static final int RC_REQUEST = 10001;

    // The helper object
    IabHelper mHelper;
    

	public SharedPreferences _prefs;

	protected String _unlockData;

	protected String _unlockSign;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.donate);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        _prefs = PreferenceManager.getDefaultSharedPreferences(this);

        // load game data

        /* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY
         * (that you got from the Google Play developer console). This is not your
         * developer public key, it's the *app-specific* public key.
         *
         * Instead of just storing the entire literal string here embedded in the
         * program,  construct the key at runtime from pieces or
         * use bit manipulation (for example, XOR with some other string) to hide
         * the actual key.  The key itself is not secret information, but we don't
         * want to make it easy for an attacker to replace the public key with one
         * of their own and then fake messages from the server.
         */
        String base64EncodedPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqyuKZ4/vhXfMAEA9JuBDZWD1bJ6A/Ms/CrSr2xTOBOahPekZfEIGR2mBIRfpnwifFCJraVSUu0adpAoDydXUD4yz9kZB0TvA6mOjUs+SxwwnNgWrVLT/tOFcorwAfN3ck3LpgNionTHOVKc8MATQE6lkFbK7cZG+hpJvF+NxxqB+4xDOGZRowZ+YwgnwlVaZEmFqxzDV2Ygi+ocl1aLFqFbCfmqsoQiTv2ShsZBQd5hh7w9csPK4jNeCVOEyFQ8gxgKVxEnqyIP0e8Vdka/2L57gPFXQz4bY8P7KL1KJCoFiznNDZebMLoFoDdTokaQHEs0Jd0dTQSwz6TXxXeIz9QIDAQAB";
        
        // Some sanity checks to see if the developer (that's you!) really followed the
        // instructions to run this sample (don't put these checks on your app!)
        
        // Create the helper, passing it our context and the public key to verify signatures with
        Log.d(TAG, "Creating IAB helper.");
        mHelper = new IabHelper(this, base64EncodedPublicKey);
        
        // enable debug logging (for a production application, you should set this to false).
        mHelper.enableDebugLogging(true);

        // Start setup. This is asynchronous and the specified listener
        // will be called once setup completes.
        Log.d(TAG, "Starting setup.");
        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
            public void onIabSetupFinished(IabResult result) {
                Log.d(TAG, "Setup finished.");

                if (!result.isSuccess()) {
                    // Oh noes, there was a problem.
                    complain("Problem setting up in-app billing: " + result);
                    return;
                }

                // Hooray, IAB is fully set up. Now, let's get an inventory of stuff we own.
                Log.d(TAG, "Setup successful. Querying inventory.");
                mHelper.queryInventoryAsync(mGotInventoryListener);
            }
        });
        
        this.findViewById(R.id.donateUnlockButton).setOnClickListener(new OnClickListener (){
			@Override
			public void onClick(View v) {
				if (mIsUnlocked)
					setScreen(2);
				else
					onUpgradeAppButtonClicked(v);
			}
        });
        
        this.findViewById(R.id.donateDisableLimeDisplay).setOnClickListener(new OnClickListener (){
			@Override
			public void onClick(View v) {
				boolean displayLimes = true;
				if (((CheckBox)v).isChecked())
				{
					displayLimes = false;
				}
				SharedPreferences.Editor editor = _prefs.edit();
            	editor.putBoolean("displayLimes", displayLimes);
            	editor.commit();
			}
        });
        
        this.findViewById(R.id.donateAdditionalButton).setOnClickListener(new OnClickListener (){
			@Override
			public void onClick(View v) {
				onDonateExtraButtonClicked(v);
			}
        });
        
        this.findViewById(R.id.donateEnableQuickLol).setOnClickListener(new OnClickListener (){
			@Override
			public void onClick(View v) {
				boolean displayLol = false;
				if (((CheckBox)v).isChecked())
				{
					displayLol = true;
				}
				SharedPreferences.Editor editor = _prefs.edit();
            	editor.putBoolean("displayLolButton", displayLol);
            	editor.commit();
			}
        });
        
        this.findViewById(R.id.donateToggleLime).setOnClickListener(new OnClickListener (){
			@Override
			public void onClick(View v) {
				boolean verified = _prefs.getBoolean("usernameVerified", false);
		        if (!verified)
		        {
		        	LoginForm login = new LoginForm(DonateActivity.this);
		        	login.setOnVerifiedListener(new LoginForm.OnVerifiedListener() {
						@Override
						public void onSuccess() {
			                if (_limeRegistered)
			                	new LimeTask().execute("remove");
			                else
			                	new LimeTask().execute("add");
						}

						@Override
						public void onFailure() {
						}
					});
		        	return;
		        }
		        else
		        {
	                if (_limeRegistered)
	                	new LimeTask().execute("remove");
	                else
	                	new LimeTask().execute("add");
		        }
			}
        });
        
        String versionName = "Unknown";
        try {
			versionName = this.getApplication().getPackageManager().getPackageInfo(getApplication().getPackageName(), 0 ).versionName;
		} catch (NameNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        ((TextView)findViewById(R.id.donateVersion)).setText("Version " + versionName);
        
        this.findViewById(R.id.changeLog).setOnClickListener(new OnClickListener (){
			@Override
			public void onClick(View v) {
				ChangeLog cl = new ChangeLog(DonateActivity.this);
		        cl.getFullLogDialog().show();
			}
        });
        
        
        updateUi();
    }

    // Listener that's called when we finish querying the items and subscriptions we own
    IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
        public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
            Log.d(TAG, "Query inventory finished.");
            if (result.isFailure()) {
                complain("Failed to query inventory: " + result);
                return;
            }

            Log.d(TAG, "Query inventory was successful.");
            
            /*
             * Check for items we own. Notice that for each purchase, we check
             * the developer payload to see if it's correct! See
             * verifyDeveloperPayload().
             */
            
            // Do we have the premium upgrade?
           
            Purchase premiumPurchase = inventory.getPurchase(SKU_DONATE_UNLOCK);
            if (premiumPurchase != null)
            {
	            _unlockData = premiumPurchase.getOriginalJson();
	            _unlockSign = premiumPurchase.getSignature();
            }
            mIsUnlocked = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
            Log.d(TAG, "User is " + (mIsUnlocked ? "PREMIUM" : "NOT PREMIUM"));
            mHasChecked = true;
            updateUi();
            setScreen(0);
            Log.d(TAG, "Initial inventory query finished; enabling main UI.");
        }
    };

    // User clicked the "Buy Gas" button
    public void onDonateExtraButtonClicked(View arg0) {
        Log.d(TAG, "donate extra button clicked.");
        

        // launch the gas purchase UI flow.
        // We will be notified of completion via mPurchaseFinishedListener
        setScreen(1);
        Log.d(TAG, "Launching purchase flow for donate.");
        
        /* TODO: for security, generate your payload here for verification. See the comments on 
         *        verifyDeveloperPayload() for more info. Since this is a SAMPLE, we just use 
         *        an empty string, but on a production app you should carefully generate this. */
        String payload = ""; 
        
        mHelper.launchPurchaseFlow(this, SKU_DONATE_EXTRA, RC_REQUEST, 
                mPurchaseFinishedListener, payload);
    }

    // User clicked the "Upgrade to Premium" button.
    public void onUpgradeAppButtonClicked(View arg0) {
        Log.d(TAG, "Upgrade button clicked; launching purchase flow for upgrade.");
        setScreen(1);
        
        /* TODO: for security, generate your payload here for verification. See the comments on 
         *        verifyDeveloperPayload() for more info. Since this is a SAMPLE, we just use 
         *        an empty string, but on a production app you should carefully generate this. */
        String payload = ""; 

        mHelper.launchPurchaseFlow(this, SKU_DONATE_UNLOCK, RC_REQUEST, 
                mPurchaseFinishedListener, payload);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);

        // Pass on the activity result to the helper for handling
        if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
            // not handled, so handle it ourselves (here's where you'd
            // perform any handling of activity results not related to in-app
            // billing...
            super.onActivityResult(requestCode, resultCode, data);
        }
        else {
            Log.d(TAG, "onActivityResult handled by IABUtil.");
        }
    }
    
    /** Verifies the developer payload of a purchase. */
    boolean verifyDeveloperPayload(Purchase p) {
        String payload = p.getDeveloperPayload();
        
        /*
         * TODO: verify that the developer payload of the purchase is correct. It will be
         * the same one that you sent when initiating the purchase.
         * 
         * WARNING: Locally generating a random string when starting a purchase and 
         * verifying it here might seem like a good approach, but this will fail in the 
         * case where the user purchases an item on one device and then uses your app on 
         * a different device, because on the other device you will not have access to the
         * random string you originally generated.
         *
         * So a good developer payload has these characteristics:
         * 
         * 1. If two different users purchase an item, the payload is different between them,
         *    so that one user's purchase can't be replayed to another user.
         * 
         * 2. The payload must be such that you can verify it even when the app wasn't the
         *    one who initiated the purchase flow (so that items purchased by the user on 
         *    one device work on other devices owned by the user).
         * 
         * Using your own server to store and verify developer payloads across app
         * installations is recommended.
         */
        
        return true;
    }

    // Callback for when a purchase is finished
    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
        public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
            Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
            if (result.isFailure()) {
                complain("Error purchasing: " + result);
                setScreen(0);
                return;
            }
            if (!verifyDeveloperPayload(purchase)) {
                complain("Error purchasing. Authenticity verification failed.");
                setScreen(0);
                return;
            }

            Log.d(TAG, "Purchase successful.");

            if (purchase.getSku().equals(SKU_DONATE_EXTRA)) {
                // bought 1/4 tank of gas. So consume it.
                Log.d(TAG, "Donate Extra. Consuming purchase.");
                mHelper.consumeAsync(purchase, mConsumeFinishedListener);
            }
            else if (purchase.getSku().equals(SKU_DONATE_UNLOCK)) {
                // bought the premium upgrade!
                Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
                alert("Thank you for donating and unlocking pointless donator features!");
                mIsUnlocked = true;
                updateUi();
                setScreen(0);
            }
        }
    };

    // Called when consumption is complete
    IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
        public void onConsumeFinished(Purchase purchase, IabResult result) {
            Log.d(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result);

            // We know this is the "gas" sku because it's the only one we consume,
            // so we don't check which sku was consumed. If you have more than one
            // sku, you probably should check...
            if (result.isSuccess()) {
                // successfully consumed, so we apply the effects of the item in our
                // game world's logic, which in our case means filling the gas tank a bit
                Log.d(TAG, "Consumption successful. Provisioning.");
            }
            else {
                complain("Error while consuming: " + result);
            }
            updateUi();
            setScreen(0);
            Log.d(TAG, "End consumption flow.");
        }
    };

	public ProgressDialog _progressDialog;

	private boolean _limeRegistered;

	private boolean _donatorStatus;

    
    // We're being destroyed. It's important to dispose of the helper here!
    @Override
    public void onDestroy() {
        super.onDestroy();
        
        // very important:
        Log.d(TAG, "Destroying helper.");
        if (mHelper != null) mHelper.dispose();
        mHelper = null;
    }

    // updates UI to reflect model
    public void updateUi() {
        // update the car color to reflect premium status or lack thereof
    	if (mHasChecked)
    	{
	        ((Button)findViewById(R.id.donateUnlockButton)).setEnabled(true);
	        if (mIsUnlocked)
	        {
	        	((Button)findViewById(R.id.donateUnlockButton)).setText("Access Donator Features");
	        	Editor edit = _prefs.edit();
	        	edit.putBoolean("enableDonatorFeatures", true);
	        	edit.commit();
	        }
	        else
	        {
	        	((Button)findViewById(R.id.donateUnlockButton)).setText("Unlock Donator Features");
	        }
    	}
        
        _limeRegistered = _prefs.getString("limeUsers", "").contains(_prefs.getString("userName", "")) && _prefs.getString("userName", "") != "";
        
        SpannableString reg = new SpannableString("Serverside Lime Status: Registered for display next to username \"" + _prefs.getString("userName", "") + "\"");
        reg.setSpan(new ForegroundColorSpan(Color.rgb(100,255,100)), 23, reg.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
        SpannableString notreg = new SpannableString("Serverside Lime Status: Not registered for display");
        notreg.setSpan(new ForegroundColorSpan(Color.rgb(255,100,100)), 23, notreg.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
        ((TextView)findViewById(R.id.donateLimeStatus)).setText(((_limeRegistered) ? reg : notreg));
        
        _donatorStatus = _prefs.getBoolean("enableDonatorFeatures", false);
        SpannableString locked = new SpannableString("Donator Status: locked");
        locked.setSpan(new ForegroundColorSpan(Color.rgb(255,100,100)), 15, locked.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
        SpannableString unlocked = new SpannableString("Donator Status: unlocked");
        unlocked.setSpan(new ForegroundColorSpan(Color.rgb(100,255,100)), 15, unlocked.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
        ((TextView)findViewById(R.id.donatorStatus)).setText(((_donatorStatus) ? unlocked : locked));
        
        ((CheckBox)findViewById(R.id.donateEnableQuickLol)).setChecked(_prefs.getBoolean("displayLolButton", false));
        ((CheckBox)findViewById(R.id.donateDisableLimeDisplay)).setChecked(!_prefs.getBoolean("displayLimes", true));
    }
    
    
    
	class LimeTask extends AsyncTask<String, Void, String>
	{
	    Exception _exception;
		private String _taskMode;
	    
        @Override
        protected String doInBackground(String... params)
        {
            try
            {
                String userName = _prefs.getString("userName", "");
                
                _taskMode = params[0];
                
                // actually upload the thing
                if (params[0] == "add")
                {
                	runOnUiThread(new Runnable(){
                		@Override public void run()
                		{
                			_progressDialog = ProgressDialog.show(DonateActivity.this, "Adding Lime", "Communicating with server...");
                		}
                	});
                	return ShackApi.addLime(userName, _unlockData, _unlockSign);
                }
                
                if (params[0] == "remove")
                {
                	runOnUiThread(new Runnable(){
                		@Override public void run()
                		{
                			_progressDialog = ProgressDialog.show(DonateActivity.this, "Removing Lime", "Communicating with server...");
                		}
                	});
                	return ShackApi.removeLime(_unlockData, _unlockSign);
                }
                
                if (params[0] == "get")
                	return ShackApi.getLimes();
                
                return null;
            }
            catch (Exception e)
            {
                Log.e("shackbrowse", "Error changing lime status", e);
                _exception = e;
                return null;
            }
        }
        
        @Override
        protected void onPostExecute(String result)
        {
        	try {
        		_progressDialog.dismiss();
        	}
        	catch (Exception e)
        	{
        		
        	}
            
            if (_exception != null)
            {
            	System.out.println("limechange: err");
                ErrorDialog.display(DonateActivity.this, "Error", "Error changing lime:\n" + _exception.getMessage());
            }
            else if (result == null)
            {
            	System.out.println("limechange: err");
                ErrorDialog.display(DonateActivity.this, "Error", "Unknown lime error.");
            }
            else if (_taskMode != "get")
            {
            	runOnUiThread(new Runnable(){
            		@Override public void run()
            		{
            			new LimeTask().execute("get");
            		}
            	});
            }
            else if (_taskMode == "get")
            {
            	System.out.println("DONATEACTIVITY: downloaded donator list: " + result);
            	SharedPreferences.Editor editor = _prefs.edit();
            	editor.putString("limeUsers", result);
            	editor.commit();
            	
            	runOnUiThread(new Runnable(){
            		@Override public void run()
            		{
            			updateUi();
            		}
            	});
            }
        }
	}
    
    public String getUsername()
    {
        AccountManager manager = AccountManager.get(this); 
        Account[] accounts = manager.getAccountsByType("com.google"); 
        List<String> possibleEmails = new LinkedList<String>();

        for (Account account : accounts)
        {
          // TODO: Check possibleEmail against an email regex or treat
          // account.name as an email address only for certain account.type values.
        	possibleEmails.add(account.name);
        }

        if(!possibleEmails.isEmpty() && possibleEmails.get(0) != null)
        {
            String email = possibleEmails.get(0);
            String[] parts = email.split("@");
            if(parts.length > 0 && parts[0] != null)
                return parts[0];
            else
                return null;
        }
        else
            return null;
    }

    // Enables or disables the "please wait" screen.
    void setScreen(int screen) {
        findViewById(R.id.screen_main).setVisibility(screen == 0 ? View.VISIBLE : View.GONE);
        findViewById(R.id.screen_wait).setVisibility(screen == 1 ? View.VISIBLE : View.GONE);
        findViewById(R.id.screen_features).setVisibility(screen == 2 ? View.VISIBLE : View.GONE);
    }

    void complain(String message) {
        Log.e(TAG, "**** TrivialDrive Error: " + message);
        alert("Error: " + message);
    }

    void alert(String message) {
        AlertDialog.Builder bld = new AlertDialog.Builder(this);
        bld.setMessage(message);
        bld.setNeutralButton("OK", null);
        Log.d(TAG, "Showing alert dialog: " + message);
        bld.create().show();
    }
    
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                Intent upIntent = new Intent(this, MainActivity.class);
                if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                    // This activity is not part of the application's task, so create a new task
                    // with a synthesized back stack.
                    TaskStackBuilder.from(this)
                            .addNextIntent(upIntent)
                            .startActivities();
                    finish();
                } else {
                    // This activity is part of the application's task, so simply
                    // navigate up to the hierarchical parent activity.
                    finish();
                }
                return true;
        }
		return false;
    }
}